Abstract
La intención del desarrollo de este proyecto es brindar las herramientas necesarias para la obtención de algunas métricas específicas que ayuden a entender de mejor manera la **microestructura** de mercados de una activo en particular. El desarrollo del mismo se divide en varias etapas, una la cual define toda la _arquitectura_ de archivos que permitan al usuario obtener dichos cálculos de manera efectiva y concisa, otra que ayude a la gestión de visualizaciones de alto nivel y finalmente una etapa de presentación de resultados, mostrado la aplicación, funcionalidad y línea de análisis del proyecto.
El desarrollo de este proyecto tiene una línea de análisis particular, y su principal objetivo se centra en la implementación de una esquema funcional para el cálculo de ciertas métricas claves que ayuden a entender de una mejor manera la microestructura de mercado correspondiente a un activo o activos en concreto. A través de las herramientas desarrolladas se espera que un nuevo y potencial usuario pueda llegar a utilizar todo la arquitectura planteada en su proceso de estudio de mercado. La intención primordial de este notebook es proveer de un ejemplo guíado que sea gráfico y visual sobre las aplicaciones y la estructura que se estuvo desarrollando a lo largo del trabajo.
Para poder correr el presente notebook es necesario haber instalado todas aquellas librerias que se encuentran descritas en el archivo adjunto en el repositorio con nombre requirements.txt. Dichas dependencias son las siguientes:
Además de todas las librerias previamente mencionadas, el correcto funcionamiento de este notebook también requiere de algunos datos externos. Estos archivos se encuentran directamente en la carpeta files adjunta dentro de este mismo repositorio:
En caso de que no se hayan instalado los paquetes dentro del ambiente virtual sobre el cual se está trabajando, se pueden instalar directamente dentro de este cuaderno. A continuación se encuentra la estructura de comandos necesarias para instalar las librerias, solo correr en caso de que no se hayan instalado previamente:
%%capture
### Install all the pip packages in the requirements.txt
import sys
!{sys.executable} -m pip install -r requirements.txt
Ya con los requerimentos computacionales bien definidos, ahora se proseguirá a cargar tanto las librerias como los scripts de python 3 para poder realizar el análisis correspondiente.
### Requierd packages
import pandas as pd
import numpy as np
import warnings
### Requierd local scripts
import data as dt
import functions as fn
import visualizations as vz
Para poder realizar este laboratorio en particular, se nos fueron proporcionados los datos previamente mencionados. A continuación se comenzará a describir un poco más a detalle la estructura de los mismos para entender de mejor manera la materia prima sobre la cual se estará trabajando.
Order Book.
Este primer conjunto de datos se encuentra bajo el formato json, por tanto se compone por una lista de diccionarios donde cada subconjuto de valores responde a un libro de órdenes del activo con clave de pizarra BTCUSDT, dicho orderbook se encuentra asociado a cada punto del tiempo que representa la llave del diccionario. La actualización de dichos libros se da en términos de segundos, por lo tanto la ventana de tiempo sobre la cual trabajaremos es de un poco más de $1$ hora. A pesar de que pareciera que no tenemos tantos datos, la realidad es que cada libro cuenta con una cantidad suficiente de datos para poder extraer información relevante a ese punto del tiempo que se encuentra asociado.
Public Trades.
Este segundo y último conjunto de datos se encuentra en formato csv, y básicamente hace referencia a los movimientos de mercado (trades) que se realizan en cada punto del tiempo, nuevamente aquí estamos trabajando con aquellos datos donde hubo una conexión entre la parte compradora y la parte vendedora del mercado para el activo BTCUSDT, es decir, en estos nuevos datos contamos con la información de aquellas órdenes que sí fueron empatadas por lo tanto estas operaciones que se efectuan son las que al final del día terminan teniendo un impacto directo en la fluctuación del precio para el activo analizado. La ventana de tiempo para la cual disponemos de esta información se encuentra alrededor de $1$ día.
Ya sabemos entonces que contamos con una lista de diccionarios donde cada llave representa un punto en el tiempo donde se contaba con ese determinado libro de órdenes, ahora lo que haremos será ir definiendo y mostrando un poco mas sobre los datos ya desde una perspectiva un poco más visual.
### Let's visualize the keys range.
ob_data = dt.ob_data_bit
range_ob = pd.to_datetime(pd.Series(list(ob_data.keys()))).sort_values()
print(f'El primer tiempo registrado está en: {range_ob[0]}, y el último en: {range_ob.tail(1).item()}')
El primer tiempo registrado está en: 2021-07-05 13:06:46.571000+00:00, y el último en: 2021-07-05 14:06:46.412000+00:00
Como podemos observar ya directamente de la descripción de los rangos para las llaves de los orderbooks contamos con un poco menos de $1$ hora de información correspondiente al día 2021-07-05 entre $1$ y $2$ de la tarde.
### Let's see how many books do we have
print(f'En una hora de tiempo contamos con {len(list(ob_data.keys())):,} libros')
En una hora de tiempo contamos con 2,401 libros
Entonces si bien pareciera que $1$ hora de tiempo no puede aportar mucha información, la realidad es que dentro de este horario contamos con alrededor de $2,401$ libros. A continuación se mostrará un poco respecto al contenido de cada orderbook, esto con la intención de alcanzar a percibir la cantidad de datos que tenemos.
### Let's see the first orderbook values
print(f'Este primer orderbook corresponde al punto en el tiempo. {range_ob[0]}:')
list(ob_data.values())[0].head(5)
Este primer orderbook corresponde al punto en el tiempo. 2021-07-05 13:06:46.571000+00:00:
| bid_size | bid | ask | ask_size | |
|---|---|---|---|---|
| 0 | 0.000400 | 28270.0 | 28275.0 | 0.025405 |
| 1 | 0.009787 | 28269.0 | 28276.0 | 0.516810 |
| 2 | 0.008168 | 28268.0 | 28277.0 | 0.005044 |
| 3 | 0.995787 | 28266.0 | 28278.0 | 0.377374 |
| 4 | 1.038704 | 28265.0 | 28280.0 | 1.179715 |
Como podemos percibir del dataframe correspondiente al primer punto del tiempo, contamos con diferentes atributos:
Todas y cada una de las llaves correspondientes a los datos del orderbook contienen un dataframe con las mismas características que se encuentra desplegado. Entonces a partir de estos valores es que se calculan las métricas que serán explicadas en la sección $4$ del documento.
Los trades públicos de cierta manera se encuentran contenidos en una estructura de datos mucho más amigable para la mayoría (csv), por tanto python se encarga de leer estos archivos y directamente transformarlos en un dataframe. A continuación observaremos un poco respecto a los atributos y dimensionas que trae consigo este archivo.
### Let's visualize the df range.
pt_data = dt.pt_data
range_pt = pd.to_datetime(pt_data.timestamp).sort_values()
print(f'El primer tiempo registrado está en: {range_pt.head(1).item()}, y el último en: {range_pt.tail(1).item()}')
El primer tiempo registrado está en: 2022-05-10 00:00:12, y el último en: 2022-05-10 23:59:38
Como podemos observar directamente de los rangos de tiempo para los public trades, vemos que el primer registro se efectuó en la madrugada del 2022-05-10 y el último de ellos se dió el mismo día justo antes de que termine, por lo tanto para este conjunto de información contamos con todo un día de transacciones.
### Let's see the public trades dataframe
print(f'Los public trades con los que contamos tienen un total de {pt_data.shape[0]:,} filas')
pt_data.head()
Los public trades con los que contamos tienen un total de 286,600 filas
| timestamp | price | amount | side | |
|---|---|---|---|---|
| 0 | 2022-05-10 08:08:07 | 31702.47 | 0.00035 | sell |
| 1 | 2022-05-10 08:08:07 | 31702.48 | 0.00263 | buy |
| 2 | 2022-05-10 08:08:07 | 31702.48 | 0.00631 | buy |
| 3 | 2022-05-10 08:08:07 | 31702.48 | 0.00264 | buy |
| 4 | 2022-05-10 08:08:07 | 31702.48 | 0.01146 | buy |
Del registro de transacciones para el BTCUSDT contamos con un total de $286,000$ operaciones, las cuales se encuentran dividas a lo largo de un día, en cuanto a los atributos del data frame contamos con el tiempo, el precio al cual se hizo la conexión, el volumen transaccionado a dicho precio en ese punto del tiempo, y finalmente contamos con la estructura de venta o compra lo cual indica de que lado se efectuó la operación.
Con la intención de eficientar tiempos computacionales lo que se decide hacer es trabajar sobre diversos scripts de python los cuales contienen las funciones predeterminadas para el cálculo de las métricas.
En esta primera serie de cálculos definidos para los orderbooks se generó una función la cual tiene la capacidad de indagar sobre las profundidades de cada libro de órdenes (claro para aquellas métricas que así lo permiten). Por términos prácticos para este laboratorio solo se estará explorando los valores obtenidos a tráves del Top of the book de manera que se deja al potencial usuario de estas funciones el poder explorar las funcionalidades sobre la profundidad de los orderbooks.
### Let's define all the metric calculations.
ob_metrics = fn.get_ob_metrics(ob_data) # Without ob dept defined
ob_metrics_depth = fn.get_ob_metrics(ob_data, 5) # With a ob depth of 5
print(f'The keys for this ob metrics are: {list(ob_metrics.keys())}')
The keys for this ob metrics are: ['update_median', 'price_levels', 'bid_volume', 'ask_volume', 'total_volume', 'spread', 'midprice', 'volume_inbalance', 'weighted_mid', 'vwap', 'stats_moments', 'ohlcv']
Esta primera métrica lo que nos describe es la mediana de tiempo que requiere cada libro de órdenes para que este se actualice, es decir a partir de este valor podemos nosotros encontrar el punto medio de la distribución para el cambio/actualización de los orderbooks. Las ventajas de utilizar la mediana sobre el promedio responden escencialmente a la presencia de valores extremos, así podemos minimizar el riesgo de sesgo para esta métrica.
### Let' see the first metric
update_median = int(ob_metrics['update_median'])
print(f'La mediana de tiempo para que se actualice un ob es de: {update_median:,} milisegundos')
La mediana de tiempo para que se actualice un ob es de: 1,500 milisegundos
De la mediana de tiempo podemos notar que los orderbooks se actualizan aproximadamente cada $1,500$ milisegundos, esto nos puede dar indicios para empezar a percibir la líquidez del activo analizado, el cual recordemos se trata de BTCUSDT.
Los niveles en cada orderbook es una medida que no requiere de gran explicación, básicamente lo que nos describe es cuantos órdenes son colocadas para cada libro de órdenes.
### Let's see the price levels
price_levels = pd.DataFrame.from_dict(ob_metrics['price_levels']).T
price_levels.columns=['Price Levels']
price_levels.head()
| Price Levels | |
|---|---|
| 2021-07-05T13:06:46.571Z | 25 |
| 2021-07-05T13:06:47.918Z | 25 |
| 2021-07-05T13:06:49.414Z | 25 |
| 2021-07-05T13:06:51.077Z | 25 |
| 2021-07-05T13:06:52.426Z | 25 |
De los niveles que tiene cada orderbook del activo analizado podemos observar que prácticamente cada ventana de tiempo cuenta con la misma cantidad de órdenes colocadas, $25$.
Como previamente se comentó el Bid corresponde al precio más alto que un comprador esta dispuesto a pagar por el activo de interés, entonces con esto en cuenta podemos decir que al nosotros obtener el volumen total de las órdenes que se estan colocando en cada orderbook para la parte Bid, podemos definir entonces la "euforia" que puede llegar a existir por parte de los compradores, a medida que más alto sea, nos indica el aumento de interés en el activo. Podemos describir este valor matemáticamente como:
$$\sum_{i=1}^{n} \text{bid size}$$Donde cada elemento $i$ representa una ventana de tiempo y $\text{bid size}$ el volumen de órdenes posicionadas por los compradores para el activo de interés.
### Let's see the bid volume levels
bid_volume = pd.DataFrame.from_dict(ob_metrics['bid_volume']).T
bid_volume.columns=['Bid Volume']
bid_volume.head()
| Bid Volume | |
|---|---|
| 2021-07-05T13:06:46.571Z | 32.100178 |
| 2021-07-05T13:06:47.918Z | 32.100178 |
| 2021-07-05T13:06:49.414Z | 32.100178 |
| 2021-07-05T13:06:51.077Z | 36.263315 |
| 2021-07-05T13:06:52.426Z | 36.263315 |
A simple vista pudiera llegar a parecer que el volumen de bid se mantiene estable, sin embargo, la realidad es que este valor se encuentra flúctuando a tráves del tiempo, las expectativas y la euforia de comprar no son estables sobre todo en activos tan volátiles como el que se está analizando.
El ask volume responde a una situación muy similar a la del bid volume solo que ahora lo hace desde la perspectiva del vendedor, nos habla de que tanto se esta dispuesto a vender en el mercado y que tantas "ganas" de liquidar las posiciones existe en determinado punto del tiempo. Matemáticamente se expresa muy parecido al bid volume
$$\sum_{i=1}^{n} \text{ask size}$$Donde cada elemento $i$ representa una ventana de tiempo y $\text{ask size}$ el volumen de órdenes posicionadas por los vendedores para el activo de interés.
### Let's see the ask volume levels
ask_volume = pd.DataFrame.from_dict(ob_metrics['ask_volume']).T
ask_volume.columns=['Ask Volume']
ask_volume.head()
| Ask Volume | |
|---|---|
| 2021-07-05T13:06:46.571Z | 31.699457 |
| 2021-07-05T13:06:47.918Z | 31.699457 |
| 2021-07-05T13:06:49.414Z | 31.699457 |
| 2021-07-05T13:06:51.077Z | 36.929183 |
| 2021-07-05T13:06:52.426Z | 36.929183 |
Haciendo una rápida comparativa con el bid volume, si nostros observamos que el ask volume empieza a crecer radicalmente podriamos empezar a concluir que existe cierto grado de incertidumbre en el activo. Altos volumenes de personas que quieren vender pueden llegar a generar caídas importantes en el precio.
El total volume básicamente es la suma de bid volume y ask volume:
$$\sum_{i=1}^{n} \text{bid size} + \text{ask size}$$### Let's see the total volume levels
total_volume = pd.DataFrame.from_dict(ob_metrics['total_volume']).T
total_volume.columns=['Total Volume']
total_volume.head()
| Total Volume | |
|---|---|
| 2021-07-05T13:06:46.571Z | 63.799635 |
| 2021-07-05T13:06:47.918Z | 63.799635 |
| 2021-07-05T13:06:49.414Z | 63.799635 |
| 2021-07-05T13:06:51.077Z | 73.192498 |
| 2021-07-05T13:06:52.426Z | 73.192498 |
El volumen total puede llegar a tener conclusiones interesantes, si bien no nos da la perspectiva respecto a las posiciones en el mercado si nos pueda ayudar a definir el interés particular que existe por el activo en cada momento del tiempo, de manera que mientrás más elevado sea este valor, podemos decir que existe algún fenómeno que esta causando expectativas (pueden ser positivas o negativas).
El spread es uno de los principales indicadores de liquidez, básicamente lo que nos define es que tal lejos están de ponerse de acuerdo la parte vendedora y la parte compradora en cada punto del tiempo. Este valor solo se define para el top of the book el cual representa el mejor bid y el mejor ask disponible en cada libro de órdenes. Matemáticamente se describe de la siguiente manera.
$$\hat{\text{ask price}} - \hat{\text{bid price}}$$Donde el simbolo $\hat{}$ hace alución a la presencia del mejor valor disponible en cada momento.
### Let's see the spread for top of the book
spread = pd.DataFrame.from_dict(ob_metrics['spread']).T
spread.columns=['Spread']
spread.head()
| Spread | |
|---|---|
| 2021-07-05T13:06:46.571Z | 5.0 |
| 2021-07-05T13:06:47.918Z | 5.0 |
| 2021-07-05T13:06:49.414Z | 5.0 |
| 2021-07-05T13:06:51.077Z | 3.0 |
| 2021-07-05T13:06:52.426Z | 3.0 |
De esta manera podemos decir mientrás más cerrado sea el spread más liquido puede ser el activo en ese momento ya estan mas cerca de poner de acuerdo los participantes del mercado. Como podemos observar en nuestros datos el spread tiende a ser relativamente elevado llegando a tocar valores incluso de $12$, sin embargo es importante considerar la escala de los datos analizados, ya que al tratarse del BTCUSDT maneja magnitudes muy amplias.
El midprice generalmente se define como el valor promedio entre el bid price y el ask price definido para el top of the book, y es justamente este precio el cual alcanza a reflejar el valor de cotización a ese momento, ya que alcanza a percibir y poderar de igual manera las expectativas tanto de compradores como de vendedores. Matemáticamente podemos expresar el midprice como:
$$\frac{\hat{\text{ask price}} + \hat{\text{bid price}}}{2}$$### Let's see the midprice for top of the book
midprice = pd.DataFrame.from_dict(ob_metrics['midprice']).T
midprice.columns=['Midprice']
midprice.head()
| Midprice | |
|---|---|
| 2021-07-05T13:06:46.571Z | 28272.5 |
| 2021-07-05T13:06:47.918Z | 28272.5 |
| 2021-07-05T13:06:49.414Z | 28272.5 |
| 2021-07-05T13:06:51.077Z | 28276.5 |
| 2021-07-05T13:06:52.426Z | 28276.5 |
De los datos obtenidos para el BTCUSDT podemos observar que el valor del midprice se encuentra fluctuando sobre valores entre $\$28,270$ y $\$28,444.5$ realmente no alcanza a presentar tantos cambios ya que pondera de igual manera las expectativas de los compradores como de los vendedores.
### Let's see the volume inbalance for top of the book
volume_inbalance = pd.DataFrame.from_dict(ob_metrics['volume_inbalance']).T
volume_inbalance.columns=['Volume Inbalance']
volume_inbalance.head()
| Volume Inbalance | |
|---|---|
| 2021-07-05T13:06:46.571Z | 0.503140 |
| 2021-07-05T13:06:47.918Z | 0.503140 |
| 2021-07-05T13:06:49.414Z | 0.503140 |
| 2021-07-05T13:06:51.077Z | 0.495451 |
| 2021-07-05T13:06:52.426Z | 0.495451 |
### Let's see the weighted midprice for top of the book
weighted_mid = pd.DataFrame.from_dict(ob_metrics['weighted_mid']).T
weighted_mid.columns=['Weighted Midprice']
weighted_mid.head()
| Weighted Midprice | |
|---|---|
| 2021-07-05T13:06:46.571Z | 28270.077503 |
| 2021-07-05T13:06:47.918Z | 28270.077503 |
| 2021-07-05T13:06:49.414Z | 28270.077503 |
| 2021-07-05T13:06:51.077Z | 28277.997729 |
| 2021-07-05T13:06:52.426Z | 28277.997729 |
### Let's see the VWAP for top of the book
vwap = pd.DataFrame.from_dict(ob_metrics['vwap']).T
vwap.columns=['VWAP']
vwap.head()
| VWAP | |
|---|---|
| 2021-07-05T13:06:46.571Z | 28274.922497 |
| 2021-07-05T13:06:47.918Z | 28274.922497 |
| 2021-07-05T13:06:49.414Z | 28274.922497 |
| 2021-07-05T13:06:51.077Z | 28275.002271 |
| 2021-07-05T13:06:52.426Z | 28275.002271 |
### Let's see the statistical moments for total orderbooks
stats_moments = pd.DataFrame.from_dict(ob_metrics['stats_moments']).T
stats_moments.columns=['Stats']
stats_moments.head()
| Stats | |
|---|---|
| median | 0.357747 |
| var | 0.012448 |
| skewness | 0.392483 |
| kurtosis | 0.196053 |
La estructura de precios OHLCV (Open-High-Low-Close-Volume), básicamente nos ayuda a entender como es que se están moviendo los precios para cada agrupación en el tiempo, es una función de agregación que agrupa y nos ayuda a entender la estructura del precio en cada momento. Para el caso de los orderbooks tenemos que esta estructura hace referencia al volumen que se encuentran colocando compradores y vendedores, no como tal al volumen de adquisición.
### Let's see the OHLCV price structure
ob_metrics['ohlcv'].head()
| Midprice | Volume | ||||
|---|---|---|---|---|---|
| open | high | low | close | Volume | |
| 2021-07-05 13:06:00+00:00 | 28272.5 | 28282.5 | 28272.5 | 28282.5 | 583.699038 |
| 2021-07-05 13:07:00+00:00 | 28296.0 | 28324.0 | 28285.0 | 28324.0 | 2607.552512 |
| 2021-07-05 13:08:00+00:00 | 28324.0 | 28324.0 | 28300.0 | 28312.0 | 2633.889410 |
| 2021-07-05 13:09:00+00:00 | 28317.0 | 28331.0 | 28313.5 | 28331.0 | 2512.929262 |
| 2021-07-05 13:10:00+00:00 | 28333.0 | 28352.0 | 28333.0 | 28338.5 | 2667.233642 |
Al contar con solamente una hora de información, se optó por agrupar para cada cambio en los mismo del tiempo, si bien pareciera que no hay mucho cambio de un tiempo a otro (sobre todo por las maginitudes a las que se mueve el BTCUSDT) la realidad es que definiendo estos deltas de $1$ min si alcanzan a percibirse determinados cambios, sobre todo en términos de volumen.
Al igual que con el cálculo de las métricas del orderbook para el cálcilo de las de public trades también se realizó una función que logre otorgar al usuario de manera precisa y concisa los valores que se desean obtener.
### Let's define all the metric calculations.
pt_metrics = fn.get_pt_metrics(pt_data)
print(f'The keys for this ob metrics are: {list(pt_metrics.keys())}')
The keys for this ob metrics are: ['buy_count', 'sell_count', 'total_count', 'diff_count', 'buy_volume', 'sell_volume', 'total_volume', 'diff_volume', 'ohlcv', 'stats_moments']
Esta métrica básicamente esta referenciada a un conteo de todas aquellas operaciones de trading que se registraron del lado del comprador. Con la intención de verla de una manera mas concisa se decide agrupar por hora.
### Let's see the trade buy count
buy_count = pt_metrics['buy_count']
buy_count.head()
| price | |
|---|---|
| hour | |
| 0 | 5789 |
| 1 | 5892 |
| 2 | 5740 |
| 3 | 6229 |
| 4 | 6265 |
Como podemos observar la mayoría de operaciones de compra por hora para el BTCUSDT se mueven entre $5,000$ y %7,000$ transacciones, pareciera ser una medida bastante normal para los niveles que maneja regularmente el activo. A partir de estos valores también se podría comenzar a intuir las expectativas del mercado para la gente que quiera comprar, mientrás mas demanda exista naturalmente el precio tenderá a subir.
El sell trade count funciona como un análogo del buy trade count solo que esta refleja las expectativas de mercado por parte de los vendedores del activo.
### Let's see the trade sell count
sell_count = pt_metrics['sell_count']
sell_count.head()
| price | |
|---|---|
| hour | |
| 0 | 6211 |
| 1 | 6008 |
| 2 | 6160 |
| 3 | 5671 |
| 4 | 5735 |
Misma conclusión, las escalas sobre las cuales se mueven las expectativas de los vendedores se encuentran entre $4,000$ y $6,000$ operaciones, un poco más baja en comparación con la contraparte de compra. Esto nos indicaría que en este día en particular la gente compró o realizó más operaciones de compra.
El total trade count básicamente corresponde a la suma de ambas partes, tanto la compradora como la vendedora, esta métrica si bien nos ayuda a darnos cuenta de la magnitud de compras realizadas por día, nos nos refleja las expectativas de cada parte del mercado.
### Let's see the trade total count
total_count = pt_metrics['total_count']
total_count.head()
| price | |
|---|---|
| hour | |
| 0 | 12000 |
| 1 | 11900 |
| 2 | 11900 |
| 3 | 11900 |
| 4 | 12000 |
En general cada hora del día se mantiene sobre los mismos niveles, entre $11,000$ y $13,000$ operaciones, no se alcanza a percibir alguna situación extraña.
Esta métrica ya nos ayuda más a entender como se interelacionan la parte compradora y vendedora del mercado entre sí. El cálculo se propuso como:
$$\text{Buy Trade Count} - \text{Sell Trade Count}$$De manera que si encontramos valores negativos para la diferencia estaríamos hablando de que en ese punto del tiempo se registraron más operaciones de venta que de compra.
### Let's see the trade diff count
diff_count = pt_metrics['diff_count']
diff_count.head()
| price | |
|---|---|
| hour | |
| 0 | -422 |
| 1 | -116 |
| 2 | -420 |
| 3 | 558 |
| 4 | 530 |
De los resultados arrojados se puede observar que existe una magnitud de inbalance considerablemente mayor a favor de los compradores ($2,216$ operaciones mas) en comparativa con el mejor desbalance para los vendedores con ($832$ operaciones mas). Esto nos indica al menos para este día analizado que sistemáticamente existió una mayor cantidad de compradores, cuestión que muy probablemente llego a impactar en el precio de cierre a final de la jornada.
### Let's see the trade buy volume
buy_volume = pt_metrics['buy_volume']
buy_volume.head()
| amount | |
|---|---|
| hour | |
| 0 | 385.22900 |
| 1 | 313.65801 |
| 2 | 315.67582 |
| 3 | 298.66418 |
| 4 | 286.82202 |
### Let's see the trade sell volume
sell_volume = pt_metrics['sell_volume']
sell_volume.head()
| amount | |
|---|---|
| hour | |
| 0 | 512.57474 |
| 1 | 437.77102 |
| 2 | 415.92031 |
| 3 | 430.73225 |
| 4 | 482.09504 |
### Let's see the trade total volume
total_volume = pt_metrics['total_volume']
total_volume.head()
| amount | |
|---|---|
| hour | |
| 0 | 897.80374 |
| 1 | 751.42903 |
| 2 | 731.59613 |
| 3 | 729.39643 |
| 4 | 768.91706 |
### Let's see the trade diff volume
diff_volume = pt_metrics['diff_volume']
diff_volume.head()
| amount | |
|---|---|
| hour | |
| 0 | -127.34574 |
| 1 | -124.11301 |
| 2 | -100.24449 |
| 3 | -132.06807 |
| 4 | -195.27302 |
### Let's see the OHLCV price structure
ohlcv_pt = pt_metrics['ohlcv']
ohlcv_pt.head()
| price | amount | ||||
|---|---|---|---|---|---|
| open | high | low | close | amount | |
| timestamp | |||||
| 2022-05-10 00:00:00 | 30075.19 | 30842.21 | 29758.78 | 30770.010 | 897.80374 |
| 2022-05-10 01:00:00 | 30722.91 | 31340.94 | 30702.40 | 30900.682 | 751.42903 |
| 2022-05-10 02:00:00 | 30883.21 | 31390.16 | 30797.60 | 31033.700 | 731.59613 |
| 2022-05-10 03:00:00 | 31045.10 | 31152.46 | 30640.13 | 30664.400 | 729.39643 |
| 2022-05-10 04:00:00 | 30682.08 | 31340.86 | 30602.80 | 31215.350 | 768.91706 |
### Let's see the statistical moments for total public trades
stats_moments_pt = pd.DataFrame.from_dict(pt_metrics['stats_moments']).T
stats_moments_pt.columns=['Stats']
stats_moments_pt.head()
| Stats | |
|---|---|
| median | -125.646475 |
| var | 4238.110708 |
| skewness | 0.161939 |
| kurtosis | -0.578542 |
### Let's see the orderbook chart. I'll select the first one with a depth of 5
vz.plot_orderbook(list(ob_data.values())[0], 5)
### Let's see the public trades chart. I'll select to see just a 1 hour behaviour
warnings.filterwarnings("ignore")
vz.plot_publictrades(pt_data, hours=1)
[1] Munnoz, 2020. Python project template. https://github.com/iffranciscome/python-project. (2021).